扫一扫
分享文章到微信
扫一扫
关注官方公众号
至顶头条
Coco:这么长时间不来,我还真想大家,实在是某人太懒了,总也不来上课。
我:这个……还真是对不起啊。主要是因为最近找了份新工作,正在赶一个项目,比较忙一些。经常会有天黑才回来的事情,所以有很长一段时间没有出现。
Coco:据我所知~某人天黑才会回家,是因为在广州总迷路,每次坐在车上的时间还没有找路的时间长,而且,还因为一些很菜的程序问题被卡住了……
我:为什么总要揭我的短呀……-_-#
Coco:hoho,上课上课~
我:好吧,上次讲了直接插入排序,我们从改进它开始。这几天,你对这个算法有什么想法没有?
Coco:在书上读到,在容器中反复的插入和删除节点是一种很低效的做法,不但速度慢,还会造成内存的碎片化,是这样子的吧。
我:很正确,所以通常来说,我们应该想办法减少插入和删除的次数。这样可以有效避免内存的碎片化。
Coco:不过对于选择插入法来说,我们只移动出现逆序的节点了,还有什么办法能更进一步减少这插入和删除的操作吗?
我:有一个办法,就是不用del和Insert进行显示的删除和插入操作,充分利用容器现有的空间,以交换节点来移动它。
Coco:不太理解。
我:由些产生的最简单的方法,用简单的数学描述来讲,是这样子的,假设集合有{a1, a2, a3,…, an},我们先从整个区间中找出最小的一个元素am,如果它不等于a1,就把它和a1交换;然后查找[a2, a3,…, an]区间,在其中找出最小的元素,如果它不等于a2,就把它和a2交换;重复这一过程,就可以对整个数组排序了。
Coco:看起来很简单呀,我去试试,测试代码段就还用上次的喽~
#以下是Coco的代码:
#Direct choice sort. It is a sample method.
def DrtChcSort(theArray):
#Move the begin of search area.
for i in range(len(Array)):
curMrk = i
#Find the min node.
for j in range(i, len(theArray)):
if theArray[j] < theArray[curMrk]:
curMrk = j
#Move it to front.
if not(curMrk == i):
theArray[curMrk], theArray[i] = theArray[i], theArray[curMrk]
Array=[6,16,10,9,15,5,11,1,19,4,14,18,0,13,3,17,12,2,8,7]
print Array
DrtChcSort(Array)
print Array
Coco:这办法比上次那个简单多了嘛,为什么当初不教我这个?
我:要你写这些算法又不是真要你实用,主要是练习一下。要不然,对python的数组排序最简单的办法应该是:Array.sort()
Coco:倒~好吧,算你说的有道理,不过这样直接交换链表中的元素:“theArray[curMrk], theArray[i] = theArray[i], theArray[curMrk]”真的可以保证内存不会碎片化,还能减少插入和删除吗?
我:老实说,我不知道,因为python对这个线性容器的操作被封装了起来,从我们这个使用层上,是看不到的。不过,我们至少避免了显示的增删操作。如果说这样编程是“可能会有坏结果”,那显示的增删操作则是“几乎一定会有坏结果”,如果在C语言这类直接操作内存的语言中,两者的效果就是很明确的了。
Coco:为什么说“几乎”?
我:因为python有它的内存管理机制,它可以进行垃圾回收,所以内存的碎片化和丢失,还是会受到控制,特别是jython,由于使用java平台,基本上不存在内存方面的困扰。不过,过于依赖它也不是好主意,至少会给虚拟机带来不必要的负担。
Coco:听起来有道理的样子,我还有一个疑问,在这个排序中,我们把当前已排序间后面的那个元素直接与未排序区间中的最小元素交换了,这会不会造成后面的未排序区间越来越乱,给我们带来额外的麻烦呢?
我:这种交换的确有增加混乱――形像的说,就像热学中的“熵”――的可能,不过如果这个算法只考虑某一个链表,也就基本上没有什么用途了。而从统计角度讲,未排序区间的“熵”
不会因此而增加。
Coco:明白了,不过这个算法太简单了,再多讲点东西吧。
我:上次有个朋友问递归的含义,你知道吗?
Coco:递推多项式,一种表达式,每一项由前一项使用的公式来决定。
我:怎么看着这么眼熟啊,从哪里贴来的?
Coco:这么快就让你看出来了啊,《金山词霸》喽~
我:倒……真会偷懒,简单的说,递归的就是指一个方法中会使用它自身。
Coco:听起来怪怪的,给个程序让我们看看吧。
我:欧几里德算法,辗转相除求最大公因子,如何?你来写这个程序吧,也不是多难
Coco:真会偷懒~
def Gba(a, b):
r = a%b
if r == 0:
return b
else:
return (b, r)
Coco:调用这个函数就可以得到a和b的最大公因子了。这种通过调用自身来进入下一步的函数就是一种递归函数吧。
我:是的,与之相对应的运算方法是迭代,也就是说通过某种方法重新记录当前状态,然后循环生成这一状态的算法,这样不用重复调用函数,在效率上比递归要好,不过可读性通常会差一些。比如以上这个Gba(a, b)的递归形式应该是这样子:
def Gba(a, b):
r = a%b
while r!=0:
a, b = b, r
r = a%b
return b
Coco:好像明白点儿了。接下来呢?
我:上次去cn99新闻组上问你说的那个很菜的问题时,有位叫Chad Netzer的朋友写了一个不错的回应,虽然我的问题很菜(Coco:这个笨蛋会不知道在python里怎么交换元素,也敢出来教别人,我真是遇人不淑呀~),但这位朋友写的回信比我的问题更有价值,如果明天有空,我把它译出来给大家分享一下。不过今天先这样吧,这两天感冒,不太舒服,明天还要上班。
Coco:感冒了不早说,别传染给我,闪~
婵犵數濮烽弫鍛婃叏閻戝鈧倹绂掔€n亞鍔﹀銈嗗坊閸嬫捇鏌涢悢閿嬪仴闁糕斁鍋撳銈嗗坊閸嬫挾绱撳鍜冭含妤犵偛鍟灒閻犲洩灏欑粣鐐烘⒑瑜版帒浜伴柛鎾寸洴閹儳煤椤忓應鎷洪梻鍌氱墛閸楁洟宕奸妷銉ф煣濠电姴锕ょ€氼參宕h箛鏃傜瘈濠电姴鍊绘晶娑㈡煕鐎c劌濡介柕鍥у瀵粙濡歌閳ь剚甯¢弻鐔兼寠婢跺﹥娈婚梺鍝勭灱閸犳牠骞冨⿰鍫濈厸闁稿本绋撹ぐ瀣煟鎼淬値娼愭繛鍙壝悾婵堢矙鐠恒劍娈鹃梺鍓插亝濞叉牠鎮″☉銏$厱閻忕偛澧介惌瀣箾閸喐鍊愭慨濠勭帛閹峰懐绮电€n亝鐣伴梻浣规偠閸斿宕¢崘鑼殾闁靛繈鍊曢崘鈧銈嗗姂閸庡崬鐨梻鍌欑劍鐎笛呯矙閹寸姭鍋撳鐓庡籍鐎规洑鍗冲畷鍗炍熼梹鎰泿闂備線娼ч悧鍡涘箠鎼淬垺鍙忔い鎺嗗亾闁宠鍨块崺銉╁幢濡炲墽鍑规繝鐢靛О閸ㄦ椽鏁嬮柧鑽ゅ仦娣囧﹪濡堕崨顔兼闂佺ǹ顑呴崐鍦崲濞戙垹骞㈡俊顖濐嚙绾板秹鏌f惔銏e妞わ妇鏁诲璇差吋閸偅顎囬梻浣告啞閹搁箖宕版惔顭戞晪闁挎繂顦介弫鍡椼€掑顒婂姛闁活厽顨嗙换娑㈠箻閺夋垹鍔伴梺绋款儐閹瑰洭寮婚敐鍛婵炲棙鍔曠壕鎶芥⒑閸濆嫭婀扮紒瀣灴閸╃偤骞嬮敃鈧婵囥亜閺囩偞鍣洪柍璇诧功缁辨捇宕掑▎鎴濆濡炪們鍔岄幊姗€骞嗗畝鍕<闁绘劙娼х粊锕傛煙閸忚偐鏆橀柛鏂跨焸閹偤宕归鐘辩盎闂佸湱鍎ら崹鐢割敂閳哄懏鍊垫慨姗嗗墻濡插綊鏌曢崶褍顏€殿喕绮欐俊姝岊槼闁革絻鍎崇槐鎾存媴缁涘娈┑鈽嗗亝缁诲牆顕f繝姘亜缁炬媽椴搁弲锝夋偡濠婂啰效闁诡喗锕㈤幊鐘活敆閸屾粣绱查梺鍝勵槸閻楀嫰宕濇惔锝囦笉闁绘劗鍎ら悡娑㈡倶閻愯泛袚闁哥姵锕㈤弻鈩冩媴閻熸澘顫掗悗瑙勬礈閸犳牠銆佸鈧幃鈺呮惞椤愩倝鎷婚梻鍌氬€峰ù鍥х暦閸偅鍙忛柟鎯板Г閳锋梻鈧箍鍎遍ˇ顖炲垂閸岀偞鐓㈡俊顖滃皑缁辨岸鏌ㄥ┑鍡╂Ц缂佲偓鐎n偁浜滈柡宥冨妿閳藉绻涢崼鐔虹煉婵﹨娅e☉鐢稿川椤斾勘鈧劕顪冮妶搴′簼婵炶尙鍠栧畷娲焵椤掍降浜滈柟鍝勬娴滈箖姊洪幐搴㈢┛濠碘€虫搐鍗遍柟鐗堟緲缁秹鏌涢锝囩畼妞ゆ挻妞藉铏圭磼濡搫顫岄悗娈垮櫘閸撴瑨鐏冮梺鍛婁緱閸犳岸宕㈤幖浣光拺闁告挻褰冩禍浠嬫煕鐎n亜顏柟顔斤耿閺佸啴宕掑☉姘箞闂佽鍑界紞鍡涘磻閸℃ɑ娅犳い鎺戝€荤壕濂告煕鐏炲墽鈽夌紒妞﹀洦鐓欓柣鐔告緲椤忣參鏌熼悡搴㈣础闁瑰弶鎸冲畷鐔兼濞戞瑦鐝¢梻鍌氬€搁崐椋庣矆娓氣偓楠炴牠顢曢妶鍌氫壕婵ê宕崢瀵糕偓瑙勬礀缂嶅﹪寮婚崱妤婂悑闁告侗鍨界槐閬嶆煟鎼达紕鐣柛搴ㄤ憾钘濆ù鍏兼綑绾捐法鈧箍鍎遍ˇ浼存偂閺囥垺鐓涢柛銉e劚婵$厧顭胯閸ㄤ即婀侀梺缁樓圭粔顕€顢旈崼鐔虹暢闂傚倷鐒︾€笛呮崲閸屾娑樜旈崨顓犲幒闂佸搫娲㈤崹娲偂閸愵亝鍠愭繝濠傜墕缁€鍫熸叏濡寧纭鹃柦鍐枛閺屾洘绻涜鐎氱兘宕戦妸鈺傗拺缂備焦锚婵洦銇勯弴銊ュ籍闁糕斂鍨藉鎾閳ユ枼鍋撻悽鍛婄叆婵犻潧妫楅埀顒傛嚀閳诲秹宕堕妸锝勭盎闂婎偄娲︾粙鎰板箟妤e啯鐓涢悘鐐靛亾缁€瀣偓瑙勬礋娴滃爼銆佸鈧幃銏$附婢跺澶�